﻿using Nop.Core;
using Nop.Core.Caching;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Media;
using Nop.Services.Configuration;
using Nop.Services.Media;
using Nop.Web.CDN.Infrastructure;
using Nop.Web.CDN.Models.Picture;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Caching;
using System.Web.Mvc;

namespace Nop.Web.CDN.Controllers
{
    public partial class PictureController : BasePublicController
    {
        #region Const

        private const int MULTIPLE_THUMB_DIRECTORIES_LENGTH = 3;

        #endregion


        private readonly CommonSettings _commonSettings;
        private readonly IWebHelper _webHelper;
        private readonly ISettingService _settingService;
        private readonly IPictureService _pictureService;
        private readonly ICacheManager _cacheManager;
        private readonly MediaSettings _mediaSettings;

        public PictureController(
            CommonSettings commonSettings,
            ISettingService settingService,
            IWebHelper webHelper,
            IPictureService pictureService,
            ICacheManager cacheManager,
            MediaSettings mediaSettings)
        {
            this._commonSettings = commonSettings;
            this._settingService = settingService;
            this._webHelper = webHelper;
            this._pictureService = pictureService;
            // new cache provider.
            this._cacheManager = cacheManager;
            this._mediaSettings = mediaSettings;
        }

        /// <summary>
        ///  get orignal picture e.g. 
        ///  dynamic picture url:
        ///   http://localhost:3000/i/d/0000015_125/25-virtual-gift-card.jpeg
        ///   http://localhost:3000/i/d/0000015/25-virtual-gift-card.jpeg
        ///   http://localhost:3000/i/d/0000015_125/default-image.gif
        ///   http://localhost:3000/i/d/avatar_300/default-avatar.jpg
        /// 
        ///  it will be captured by web server and fetch pictureId, height, width,it go through the cache 
        ///  then redirect 
        /// </summary>
        /// <param name="property">the picture information {id-w-h}=00001-w200-h200</param>
        /// <param name="name"> the picture seo name.</param>
        [HttpGet]
        public ActionResult DynamicPicture(string property, string name)
        {
            var extension = Path.GetExtension(name);
            PicturePathInfoModel pictureInfo = ExtractPictureInfo(property, extension);
            if (pictureInfo == null)
            {
                return Content(string.Empty);
            }
            else
            {
                try
                {
                    // get local picture path here via cache or local file reader.
                    var localFullPicturePath = GenerateThumbPictureUrl(pictureInfo);
                    var fileLastModifiedDate = System.IO.File.GetLastWriteTime(localFullPicturePath);

                    // If return false, nothing has changed, diretly ouput 304.
                    if (this.SetEtagLastModified(Request, Response, fileLastModifiedDate) == false)
                    {
                        return this.NotModified(Response);
                    }

                    // show picture files stream to client.
                    return new FileStreamResult(new FileStream(localFullPicturePath, FileMode.Open), GetContentType(localFullPicturePath));
                }
                catch (Exception ex)
                {
                    base.LogException(ex);
                    return Content(string.Empty);
                }
            }
        }
        /// <summary>
        /// Dynamics the picture with SEO filename. 
        /// match  http://localhost:3000/i/d/0000015_250.jpg  (id_maxSize)
        ///       http://localhost:3000/i/d/0000015.jpg (id)
        ///       http://localhost:3000/i/d/default-image.gif
        ///       http://localhost:3000/i/d/default-avatar.jpg
        /// 
        /// </summary>
        /// <returns>The picture with SEO filename.</returns>
        /// <param name="property">Property.</param>
        [HttpGet]
        public ActionResult DymamicPictureWithoutSEOFilename(string name)
        {
            var extension = Path.GetExtension(name);
            // remove extention.   00001_250.jpg--> 00001_250
            var property = Path.GetFileNameWithoutExtension(name);

            PicturePathInfoModel pictureInfo = ExtractPictureInfo(property, extension);

            if (pictureInfo == null)
            {
                return Content(string.Empty);
            }
            else
            {
                try
                {
                    // get local picture path here via cache or local file reader.
                    var localFullPicturePath = GenerateThumbPictureUrl(pictureInfo);
                    var fileLastModifiedDate = System.IO.File.GetLastWriteTime(localFullPicturePath);

                    // If return false, nothing has changed, diretly ouput 304.
                    if (this.SetEtagLastModified(Request, Response, fileLastModifiedDate) == false)
                    {
                        return this.NotModified(Response);
                    }

                    return new FileStreamResult(new FileStream(localFullPicturePath, FileMode.Open), GetContentType(localFullPicturePath));
                }
                catch (Exception ex)
                {
                    base.LogException(ex);
                    return Content(string.Empty);
                }
            }
        }

        [NonAction]
        private string GenerateThumbPictureUrl(PicturePathInfoModel pictureInfo)
        {
            string url = string.Empty;
            // if picturId = 0 it should be default picture.
            if (pictureInfo != null && pictureInfo.PictureId != 0)
            {
                //Picture picture = pictureService.GetPicture(pictureInfo.PictureId);
                var pictureCacheKey = pictureInfo.GetPictureHashKey();
                // default cache 60mins.
                url = _cacheManager.Get(pictureCacheKey, () =>
                {
                    return _pictureService.GetPictureUrl(pictureInfo.PictureId, pictureInfo.TargetSize, showDefaultPicture: true, storeLocation: null, defaultPictureType: pictureInfo.PictureType);
                });
            }
            else
            {
                // if pictureInfo has exist use it.
                if (pictureInfo != null)
                {
                    url = _pictureService.GetDefaultPictureUrl(pictureInfo.TargetSize, pictureInfo.PictureType);
                }
                else
                {
                    // if can't resolve current picture url, just return default-image.gif.
                    url = _pictureService.GetDefaultPictureUrl(0, PictureType.Entity);
                }

            }
            // convert url merchine local absolute url.
            // http://localhost:2000/content/images/thumbs/0000015_25-virtual-gift-card_125.jpeg
            var thumbFileName = Path.GetFileName(url);
            // deal for /content/images/default-image.gif
            if (!string.IsNullOrEmpty(url) && !url.Contains("/thumbs/"))
            {
                var thumbsDirectoryPath = _webHelper.MapPath("~/content/images");
                return Path.Combine(thumbsDirectoryPath, thumbFileName);
            }
            return GetThumbLocalPath(thumbFileName);

        }
        /// <summary>
        /// Get picture (thumb) local path
        /// </summary>
        /// <param name="thumbFileName">Filename</param>
        /// <returns>Local picture thumb path</returns>
        protected virtual string GetThumbLocalPath(string thumbFileName)
        {
            var thumbsDirectoryPath = _webHelper.MapPath("~/content/images/thumbs");
            if (_mediaSettings.MultipleThumbDirectories)
            {
                //get the first two letters of the file name
                var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(thumbFileName);
                if (fileNameWithoutExtension != null && fileNameWithoutExtension.Length > MULTIPLE_THUMB_DIRECTORIES_LENGTH)
                {
                    var subDirectoryName = fileNameWithoutExtension.Substring(0, MULTIPLE_THUMB_DIRECTORIES_LENGTH);
                    thumbsDirectoryPath = Path.Combine(thumbsDirectoryPath, subDirectoryName);
                    if (!System.IO.Directory.Exists(thumbsDirectoryPath))
                    {
                        System.IO.Directory.CreateDirectory(thumbsDirectoryPath);
                    }
                }
            }
            var thumbFilePath = Path.Combine(thumbsDirectoryPath, thumbFileName);
            return thumbFilePath;
        }
        /// <summary>
        /// Extracts the picture info. 
        /// </summary>
        /// <returns>The picture info.</returns>
        /// <param name="property">only for the format :{id-max}=00001-250|| default-avatar</param>
        [NonAction]
        private PicturePathInfoModel ExtractPictureInfo(string property, string extension)
        {
            PicturePathInfoModel pictureInfo = null;

            // if property is "default-avatar", "default-image" ...
            var defaultPictures = new List<string>(){
                "default-avatar",
                "default-image"
            };
            // if is default picture.
            if (defaultPictures.Contains(property))
            {
                pictureInfo = new PicturePathInfoModel
                {
                    PictureId = 0,
                    Extension = extension,
                    TargetSize = 0
                };
                if (property.Contains("avatar"))
                {
                    pictureInfo.PictureType = PictureType.Avatar;
                }
                else
                {
                    pictureInfo.PictureType = PictureType.Entity;
                }
                // directly return.
                return pictureInfo;
            }

            string[] matches = Regex.Split(property, "[-_?]");
            if (matches != null)
            {
                switch (matches.Length)
                {
                    // pictureId, maxSize
                    case 2:
                        var first = matches[0].ToString().ToLower();
                        string match_1 = matches[1];
                        int TargetSize = 0;
                        try
                        {
                            TargetSize = Int32.Parse(match_1);
                        }
                        catch (Exception) { }

                        pictureInfo = new PicturePathInfoModel
                        {
                            TargetSize = TargetSize
                        };
                        switch (first)
                        {
                            case "avatar":
                                pictureInfo.PictureType = PictureType.Avatar;
                                pictureInfo.PictureId = 0;
                                break;
                            case "entity":
                                pictureInfo.PictureType = PictureType.Entity;
                                pictureInfo.PictureId = 0;
                                break;
                            default:
                                pictureInfo.PictureType = PictureType.Entity;
                                try
                                {
                                    pictureInfo.PictureId = Int32.Parse(first);
                                }
                                catch (Exception) { pictureInfo.PictureId = 0; }
                                break;
                        }
                        pictureInfo.Extension = extension;
                        break;
                    // picture id.
                    case 1:
                        pictureInfo = new PicturePathInfoModel
                        {
                            PictureId = Int32.Parse(matches[0]),
                            TargetSize = 0,
                            PictureType = PictureType.Entity,
                            Extension = extension
                        };
                        break;
                }

            }
            return pictureInfo;
        }

        [NonAction]
        private string GetContentType(string path)
        {
            string contentType = "image/jpeg";

            switch (Path.GetExtension(path))
            {
                case ".bmp":
                    contentType = "image/bmp";
                    break;
                case ".gif":
                    contentType = "image/gif";
                    break;
                case ".jpg":
                    contentType = "image/jpeg";
                    break;
                case ".png":
                    contentType = "image/png";
                    break;
            }
            return contentType;
        }
        [NonAction]

        private ImageFormat GetImageFormat(String path)
        {
            switch (Path.GetExtension(path))
            {
                case ".bmp": return ImageFormat.Bmp;
                case ".gif": return ImageFormat.Gif;
                case ".jpg": return ImageFormat.Jpeg;
                case ".png": return ImageFormat.Png;
                default: break;
            }
            return ImageFormat.Jpeg;
        }
    }
}
